/*
 *  game.c
 *
 *  $Id: game.c 21 2009-08-22 01:59:26Z nramsbottom $	
 *
 */

#include <stdlib.h>
#include <memory.h>
#include <sys/types.h>
#include <time.h>

#include "game.h"
#include "display.h"
#include "log.h"
#include "input.h"
#include "language.h"

// NGR: Only needs four characters, but allow for silly inpt
//	    that's caught in validation.
static char move[10];

static board_t board;
static player_t players[MAX_PLAYERS];
static player_t* p1;
static player_t* p2;
static int current;				// whoose move (player index)
static player_t* winner = NULL;
static int deadlocked = 0;

static void game_setdeadlocked(void) {
	deadlocked = 1;
} //

static int game_isboardfull(void) {
	int x,y;
	for (x=1;x<4;x++) {
		for (y=1;y<4;y++) {
			if (game_getboardtoken(x, y) == TOKEN_NONE)
				return 0; // false. we found at least one empty position
		}
	}
	return 1; // true, we didn't break out of the loops so all must be filled
} //

static void game_new(void) {

	memset(&board, 0, sizeof(board_t));
	memset(&players, 0, sizeof(player_t) * 2);
	
	p1 = &players[0];
	p2 = &players[1];
	
	// assign player tokens
	p1->token = 'X';
	p2->token = '0';
	p1->id = 1;
	p2->id = 2;
	
	//printf("Player1 Name: ");
	printf(language_getstring(STRING_PLAYER1NAME));
	input_readline(p1->name, sizeof(p1->name));
	
	//printf("Player2 Name: ");
	printf(language_getstring(STRING_PLAYER2NAME));
	input_readline(p2->name, sizeof(p2->name));
	
	printf(language_getstring(STRING_GAMEBEGIN));
	printf(language_getstring(STRING_PLAYER1DETAIL), p1->name);
	printf(language_getstring(STRING_PLAYER2DETAIL), p2->name);
	//printf("Thank you. Now the game can begin\n");
	//printf("\tPlayer 1 (%s): X\n", p1->name);
	//printf("\tPlayer 2 (%s): 0\n", p2->name);

	// determine who will go first by picking a random player index
	srand(time(NULL));
	current = rand() % MAX_PLAYERS;
	
	printf(language_getstring(STRING_GOFIRST), players[current].name);
	//printf("\n\t%s will go first!.\n", players[current].name);
	
} //

void game_run(void) {

	char again;
	
start:
	
	game_new();

	winner = NULL;
	deadlocked = 0;
	
	// display the game field at the start
	display_drawfield(&board);
	
	do {
		game_getmove();
		display_drawfield(&board);
		game_toggleplayer();
		winner = game_haswinner();
	} while ( winner == NULL && !deadlocked );
	
	if (deadlocked) {
		//printf("\nIt's a tie!!\n");
		printf(language_getstring(STRING_ITADRAW));
	} else {
		//printf("\nCongratulations %s, you are the winner!!\n", winner->name);
		printf(language_getstring(STRING_YOUAREWINNER), winner->name);
	}
	
askagain:
	
	printf(language_getstring(STRING_PLAYAGAIN));
	//printf("Play again? [y/n]: ");
	again = getchar();
	getchar(); // read whitespace char
	if (again == 'y' || again == 'Y')
		goto start;
	else if (again == 'n' || again == 'N')
		return;
	goto askagain;
	
} //


// returns NULL if no winner, and a pointer to 
// the winning player if we found one.
static player_t* game_haswinner() {
	
	// check to see if any row has three identical tokens
	int x, y;
	int rowscore;
	unsigned char token;
	unsigned char lasttoken;
	
	// check horizontals
	for (x=1;x<4;x++) {
		
		rowscore = 0;
		lasttoken = TOKEN_NONE;
	
		for (y=1;y<4;y++) {
		
			token = game_getboardtoken(x, y);
		//	printf("DEBUG: x=%d; y=%d; token=%c; lasttoken=%c\n", x, y, token, lasttoken);
			if (token != TOKEN_NONE) {
				if (y == 1)
					rowscore++; // first column, not empty
				else if (token == lasttoken)
					rowscore++; // column matches last column
			}
			
			lasttoken = token;
		}
		//printf("DEBUG: row=%d; score=%d\n", x, rowscore);
		if (rowscore == 3) {
			// it's a winning row and the last token wins
			return game_findplayerbytoken(lasttoken);
		}
	}
	
	// check for vertical wins
	for (y=1;y<4;y++) {
			// scan column at a time
		rowscore = 0;
		lasttoken = TOKEN_NONE;
		
		for (x=1;x<4;x++) {
			token = game_getboardtoken(x, y);
			if (token != TOKEN_NONE) {
				if (x == 1)
					rowscore++; // first item, not empty
				else if (token == lasttoken)
					rowscore++;
				lasttoken = token;
			}
		} 
		// in this context, rowscore refers to a column (a vertical row)
		if (rowscore == 3)
			return game_findplayerbytoken(lasttoken);
	}
	
	// check for diagonal lines
	token = game_getboardtoken(1, 1);
	
	// check upper-left to lower right
	if (token == game_getboardtoken(2, 2) && 
		token == game_getboardtoken(3, 3)) {
		return game_findplayerbytoken(token);
	}

	// check upper right to lower left
	token = game_getboardtoken(1, 3);

	if (token == game_getboardtoken(2, 2) &&
		token == game_getboardtoken(3, 1)) {
		return game_findplayerbytoken(token);
	}
	
	// TODO: Deadlock check. If all the board positions are used
	//       up at the point and no winner was already found then
	//		 it must be a deadlocked game. How to communicate this
	//		 back to the gmae loop?
	if (game_isboardfull()) {
		game_setdeadlocked();
	}
	
	return NULL;
} //

static void game_getmove() {
	
start:
	
	printf(language_getstring(STRING_MOVEPROMPT), players[current].id, players[current].name);
	//printf("Player %d (%s) (x,y): ", players[current].id, players[current].name);
	input_readline(move, sizeof(move));
	
	int x, y;
	char* val;
	
	// nothing entered?
	if (strlen(move) == 0)
		goto start;
	
	// split the input on comma
	val = strtok(move, ",");
	if (val)
		x = atoi(val);
	else
		x = -1;
	
	// get second input value, after the comma
	val = strtok(NULL, ",");
	
	if (val)
		y = atoi(val);
	else
		y = -1;
	
	// validate input
	if (x < 1 || x > 3 || y < 1 || y > 3) {
		//printf("\nThat's not a valid selection. Please try again.\n");
		printf(language_getstring(STRING_INVALIDMOVE));
		goto start;
	}
	
	log_write("DEBUG: Player %d (index=%d): Move x=%d, y=%d\n", players[current].id, current, x, y);
	
	// get the current token from that position on the board
	unsigned char cell = game_getboardtoken(x, y);
	
	// check if the position is empty
	if (cell == TOKEN_NONE) {
		
		// it's empty. move accepted. update the board
		game_setboardtoken(x, y, players[current].token);
										 
	} else {
	
		// there's already a token on the board at that location.
		// display a message
		
		player_t* p = game_findplayerbytoken(cell);
		
		if (players[current].id == p->id) {
			// it's the current player's token
			//printf("Sorry, but you have already moved there.\n");
			printf(language_getstring(STRING_BADMOVEYOU));
		} else {
			// it's the other player's token
			//printf("Sorry, but %s has already moved there.\n", p->name);
			printf(language_getstring(STRING_BADMOVEOTHER), p->name);
		}
		goto start;
	}
	
} //

static void game_toggleplayer() {
	if (current < MAX_PLAYERS - 1)
		current++; // next player
	else
		current = 0; // or reset to first
} //
		
static player_t* game_findplayerbytoken(char token) {
	int n;
	for (n=0;n<MAX_PLAYERS;n++) {
		if (players[n].token == token) {
			return &players[n];
		}
	}
	return NULL;
} //


// translates the x,y co-ordinates to an cell index and returns
// the value stored in that cell.
unsigned char game_getboardtoken(int x, int y) {
	int index = (--x * 3) + --y;
	return board.cell[index];
} //

// translates the x,y co-ordinates to an cell index and updates
// the value stored in that cell.
void game_setboardtoken(int x, int y, unsigned char token) {
	// NOTE: x and y are values between 1 and 3
	int index = (--x * 3) + --y;
	board.cell[index] = token;
} //
